package account.webapi;

import account.pojo.StudentAccount;
import account.service.StudentAccountService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import javax.validation.ValidationException;
import javax.validation.constraints.PastOrPresent;
import java.io.Serializable;
import java.time.LocalDate;
import java.util.Optional;

/**
 * 后端API接口
 */
@Controller
@RequestMapping("/accounts")
public class StudentAccountController {

    public StudentAccountController(StudentAccountService studentAccountService) {
        this.studentAccountService = studentAccountService;
    }

    private final StudentAccountService studentAccountService;

    @PostMapping()
    public @ResponseBody
    Result<?> createAccount(@Valid @RequestBody AccountCreation creation) throws ValidationException {
        StudentAccount studentAccount = new StudentAccount();
        studentAccount.setId(null);
        studentAccount.setRealName(creation.getRealName());
        studentAccount.setDob(creation.getDob());
        studentAccount.setPrimaryMobilePhoneNumber(creation.getPrimaryMobilePhoneNumber());
        StudentAccount created = studentAccountService.createAccount(studentAccount);
        return new ResultSuccess<>(MaskedStudentAccount.of(created));
    }

    /**
     * Account成员字段更新
     *
     * @param id           库表行号ID
     * @param modification 入参
     * @return 成功时返回成功修改的记录条数=1
     */
    @PutMapping("/{id}")
    public @ResponseBody
    Result<Long> updateAccount(
            @PathVariable Long id,
            @Valid @RequestBody AccountModification modification) throws AppRuntimeException, ValidationException {
        if (!studentAccountService.existsById(id)) {
            throw new AppRuntimeException(AppErrorCode.NOT_FOUND, "Can not find student account with id=" + id);
        }
        StudentAccount studentAccount = new StudentAccount();
        studentAccount.setId(id);
        studentAccount.setRealName(modification.getRealName());
        studentAccount.setDob(modification.getDob());
        studentAccount.setPrimaryMobilePhoneNumber(modification.getPrimaryMobilePhoneNumber());
        long result = studentAccountService.update(studentAccount);
        return new ResultSuccess<>(result);
    }

    @GetMapping("/{id}")
    public @ResponseBody
    Result<?> queryById(@PathVariable Long id) throws AppRuntimeException {
        final Optional<StudentAccount> found = studentAccountService.findById(id);
        MaskedStudentAccount masked = found.map(MaskedStudentAccount::of)
                .orElseThrow(() -> new AppRuntimeException(AppErrorCode.NOT_FOUND, "Can not find student account with id=" + id));
        return new ResultSuccess<>(masked);
    }

    @GetMapping()
    public @ResponseBody
    Result<?> queryByPage(
            @RequestParam(value = "page_index", defaultValue = "0") Integer pageIndex,
            @RequestParam(value = "size", defaultValue = "10") Integer size) {
        size = Math.max(size, 1);
        size = Math.min(size, 50);
        Pageable pageable = PageRequest.of(pageIndex, size);
        Page<StudentAccount> accounts = studentAccountService.findAll(pageable);
        return new ResultSuccess<>(accounts.map(MaskedStudentAccount::of));
    }

    private static class AccountCreation extends AbstractAccountRequest {
    }

    private static class AccountModification extends AbstractAccountRequest {
    }

    private static abstract class AbstractAccountRequest implements Serializable {
        /**
         * 真名
         */
        private String realName;

        public String getRealName() {
            return realName;
        }

        public void setRealName(String realName) {
            this.realName = realName;
        }

        /**
         * 出生日期年月日 DOB = Date Of Birth
         * <p>
         * 备注: 没有默认值, 允许不登记出生日期。
         */
        @PastOrPresent(message = "出生日期错误！该日期属于未来")
        private LocalDate dob;

        public LocalDate getDob() {
            return dob;
        }

        public void setDob(LocalDate dob) {
            this.dob = dob;
        }

        /**
         * 主手机号码
         */
        private String primaryMobilePhoneNumber;

        public String getPrimaryMobilePhoneNumber() {
            return primaryMobilePhoneNumber;
        }

        public void setPrimaryMobilePhoneNumber(String primaryMobilePhoneNumber) {
            this.primaryMobilePhoneNumber = primaryMobilePhoneNumber;
        }

        /**
         * 转换为可读字符串
         */
        @Override
        public String toString() {
            return String.format("%s{realName=%s, dob=%s, primaryMobilePhoneNumber=%s}",
                    this.getClass().getSimpleName(), realName, dob, primaryMobilePhoneNumber);
        }
    }
}
